/*
    日志器类实现——对多个功能模块的整合
    1.抽象日志器基类
    2.根基不同的实现方式 同步/异步派生出不同的子类
*/

#ifndef __M_LOGGER_H__
#define __M_LOGGER_H__

#include <thread>
#include <mutex>
#include <atomic>
#include <vector>
#include <cstdarg>
#include <unordered_map>
#include "util.hpp"
#include "format.hpp"
#include "level.hpp"
#include "sink.hpp"
#include "message.hpp"
#include "buffer.hpp"
#include "looper.hpp"

namespace mylog{

    // 需要在这里提前声明 LoggerManager 因为 Logger 类要用到它
    class LoggerManager; 

    // 1.日志器基类
    class Logger{
    public:
        using ptr = std::shared_ptr<Logger>;

        Logger(const std::string &logger_name, const loglevel::value limit_level,
               Formatter::ptr &formatter, std::vector<LogSink::ptr> &sinks)
            : _logger_name(logger_name),
              _limit_level(limit_level),
              _formatter(formatter),
              _sinks(sinks.begin(), sinks.end())
        {}

        const std::string& name(){
            return _logger_name;
        }

        // 不同的日志等级封装对应的日志消息并格式化
        void DEBUG(const std::string &filename, const size_t line, const char *fmt, ...){
            // 1.先判断当前日志等级是否大于限制等级
            loglevel::value level = loglevel::value::DEBUG;
            if (level >= _limit_level){
               // 2.准备可变参数：用 va_start 初始化 va_list 并传给 Init 最后用 va_end 清理
               va_list al;
               va_start(al, fmt);
               // 使用va_copy创建副本传递给Init（修复Release优化问题）
               va_list al_copy;
               va_copy(al_copy, al);
               Init(level, filename, line, fmt, al_copy);
               va_end(al_copy);
               va_end(al);
            }
        }
        void INFO(const std::string &filename, const size_t line, const char *fmt, ...){
            loglevel::value level = loglevel::value::INFO;
            if (level >= _limit_level){
                va_list al;
                va_start(al, fmt);
                va_list al_copy;
                va_copy(al_copy, al);
                Init(level, filename, line, fmt, al_copy);
                va_end(al_copy);
                va_end(al);   
            }
        }
        void WARNING(const std::string &filename, const size_t line, const char *fmt, ...){
            loglevel::value level = loglevel::value::WARNING;
            if (level >= _limit_level){
                va_list al;
                va_start(al, fmt);
                va_list al_copy;
                va_copy(al_copy, al);
                Init(level, filename, line, fmt, al_copy);
                va_end(al_copy);
                va_end(al);
            }
        }
        void ERROR(const std::string &filename, const size_t line, const char *fmt, ...){
            loglevel::value level = loglevel::value::ERROR;
            if (level >= _limit_level){
                va_list al;
                va_start(al, fmt);
                va_list al_copy;
                va_copy(al_copy, al);
                Init(level, filename, line, fmt, al_copy);
                va_end(al_copy);
                va_end(al);
            }
        }
        void FATAL(const std::string &filename, const size_t line, const char *fmt, ...){
            loglevel::value level = loglevel::value::FATAL;
            if (level >= _limit_level){
                va_list al;
                va_start(al, fmt);
                va_list al_copy;
                va_copy(al_copy, al);
                Init(level, filename, line, fmt, al_copy);
                va_end(al_copy);
                va_end(al);
            }
        }

    private:
        void Init(loglevel::value level, const std::string &filename, const size_t line, const char *fmt, va_list al){
            // 3.根据不定参数获取日志消息有效载荷
            char buffer[1024];
            int n = vsnprintf(buffer, sizeof(buffer), fmt, al);
            va_end(al);
            logmsg msg(level, filename, line, _logger_name, buffer);
            // 4.将获取到的有效载荷进行日志格式化
            std::stringstream ss;
            _formatter->format(ss, msg);
            // 5.调用日志落地接口 将日志落地输出
            log(ss.str().c_str(), ss.str().size());
        }

    protected:
        // 抽象接口 不同的子类落地方式不同 同步/异步
        virtual void log(const char *data, const size_t len) = 0;

    protected:
        // 日志器基类提供一个stop停止工作的空实现 只有需要该特殊行为的派生类才需要重写
        virtual void stop() {}

        // 依次让日志落地对象清空系统缓冲区
        void flush_all_sinks(){
            if(_sinks.empty()){
                return;
            }
            for(auto &sink : _sinks){
                sink->flushbuffer();
            }
        }

        // 将日志器管理器类声明为日志器的友元类
        friend class LoggerManager;

    protected:
        std::mutex _mutex;                              // 互斥锁
        std::string _logger_name;                       // 日志器名称
        std::atomic<loglevel::value> _limit_level;      // 日志限制等级
        Formatter::ptr _formatter;                      // 指向日志格式化对象的智能指针
        std::vector<LogSink::ptr> _sinks;               // 日志落地数组——同一个日志器可以向多个位置进行日志落地输出
    };

    // 2.根据基类派生不同的子类
    // 同步日志器子类
    class SyncLogger : public Logger {
    public:
        SyncLogger(const std::string &logger_name, const loglevel::value limit_level,
               Formatter::ptr &formatter, std::vector<LogSink::ptr> &sinks)
        :Logger(logger_name, limit_level, formatter, sinks)
        {}
        void log(const char *data, const size_t len) override {
            std::unique_lock<std::mutex> lock(_mutex);
            // 错误点三:重复加锁
            for (auto &sink : _sinks)
            {
                sink->log(data, len);
            }
        }
    };

    // 异步日志器子类
    class AsyncLogger : public Logger, public std::enable_shared_from_this<AsyncLogger> {
    public:
        AsyncLogger(const std::string &logger_name, const loglevel::value limit_level,
                    Formatter::ptr &formatter, std::vector<LogSink::ptr> &sinks)
            : Logger(logger_name, limit_level, formatter, sinks)
        // 错误点:
        //     // 因为回调函数这里是成员函数存在第一个默认的this指针 所以这里用绑定的方式绑定第一个参数进行传递
        //   _looper(std::make_shared<AsyncLooper>(std::bind(&AsyncLogger::callback, this, std::placeholders::_1),
        //     looper_type))
        {}

        // 新增一个start方法 启动异步日志器的工作器
        void start(LooperType looper_type){
            auto self = shared_from_this();
            _looper = std::make_shared<AsyncLooper>([self](Buffer &buffer)
                                                    { self->callback(buffer); }, looper_type);
        }

        void log(const char *data, const size_t len) override {
            // 异步日志器中 业务线程只需要把格式化后的日志写入到工作器的生产缓冲区即可
            _looper->push(data, len);
        }

        // 异步日志器重写“停止工作”该特殊行为
        void stop() override {
            _looper->stop();
        }

    private:
        void callback(Buffer &buffer){
            // 将消费缓冲区中的可读数据进行落地输出
            for (auto &sink : _sinks)
            {
                sink->log(buffer.ReadBegin(), buffer.ReadSize());
            }
        }

    private:
        AsyncLooper::ptr _looper;
    };

    // 枚举日志器类型 同步/异步
    enum class LoggerType{
        SYNC_LOGGER,
        ASYNC_LOGGER
    };
    // 建造者模式创建日志器对象
    // 建造者基类
    class LoggerBuilder{
    public:
        LoggerBuilder()
        :_logger_type(LoggerType::SYNC_LOGGER),
        _limit_level(loglevel::value::DEBUG),
        _looper_type(LooperType::ASYNC_ASFE)
        {}

        void BuildLoggerType(const LoggerType &logger_type){
            _logger_type = logger_type;
        }
        void BuildLoggerName(const std::string &logger_name){
            _logger_name = logger_name;
        }
        void BuildLoggerLevel(const loglevel::value &level){
            _limit_level = level;
        }
        void BuildFormatter(const std::string &pattern){
            _formatter = std::make_shared<Formatter>(pattern);
        }
        template<typename SinkType, typename... Args>
        void BuildSink(Args &&... args){
            // 调用工厂接口生成对应的日志落地对象 存放到数组中
            LogSink::ptr psink = SinkFactory::create<SinkType>(std::forward<Args>(args)...);
            _sinks.push_back(psink);
        }

        // 为异步日志器提供的设置非安全工作器类型接口
        void SetUnsafeType(){
            _looper_type = LooperType::ASYNC_UNSAFE;
        }

        // 抽象接口 生成日志器对象
        virtual Logger::ptr Build() = 0;

    protected:
        LoggerType _logger_type;
        std::string _logger_name;
        loglevel::value _limit_level;
        Formatter::ptr _formatter;
        std::vector<LogSink::ptr> _sinks;
        LooperType _looper_type;         // 异步日志器的工作器类型
    };

    // 根据建造者基类派生出不同的建造者子类
    // 局部日志器建造者子类
    class LocalLoggerBuilder : public LoggerBuilder {
    public:
        Logger::ptr Build() override {
            assert(!_logger_name.empty());
            if(_formatter == nullptr){
                _formatter = std::make_shared<Formatter>();
            }
            if(_sinks.empty()){
                _sinks.push_back(SinkFactory::create<StdcoutSink>());
            }
            // 根据不同的日志器类型 返回不同的日志器对象
            if (_logger_type == LoggerType::ASYNC_LOGGER){
                auto async_logger = std::make_shared<AsyncLogger>(_logger_name, _limit_level, _formatter, _sinks);
                async_logger->start(_looper_type);
                return async_logger;
            }
            return std::make_shared<SyncLogger>(_logger_name, _limit_level, _formatter, _sinks);
        }
    };

    // 日志器管理者类 采用单例模式实现
    class LoggerManager{
    public:
        static LoggerManager& GetInstance(){
            static LoggerManager _eton;
            return _eton;
        }
        void addlogger(const Logger::ptr &logger){
            if(findlogger(logger->name())){
                return;
            }
            std::unique_lock<std::mutex> lock(_mutex);
            _loggers.insert({logger->name(), logger});
        }
        bool findlogger(const std::string &loggername){
            std::unique_lock<std::mutex> lock(_mutex);
            auto it = _loggers.find(loggername);
            if (it == _loggers.end()){
                return false;
            }
            return true;
        }
        Logger::ptr getlogger(const std::string &loggername){
            std::unique_lock<std::mutex> lock(_mutex);
            auto it = _loggers.find(loggername);
            if (it == _loggers.end()){
                return Logger::ptr();
            }
            return it->second;
        }
        Logger::ptr getdefaultlogger(){
            return _default_logger;
        }

        void shutdown(){
            // 所用被管理异步日志器的工作器停止工作 阻塞业务主线程 让后台工作线程完成剩余的数据处理 写入到系统缓冲区
            // 同时让所有日志落地对象清空系统缓冲区 防止数据丢失
            std::unique_lock<std::mutex> lock(_mutex);
            for(auto & pair : _loggers){
                pair.second->stop();
                pair.second->flush_all_sinks();
            }
            // 清空哈希表
            _loggers.clear();
        }

    private:
        // 构造私有化
        LoggerManager(){
            // 构造一个默认的日志器
            std::unique_ptr<LoggerBuilder> builder(new LocalLoggerBuilder());
            std::string name = "default";
            builder->BuildLoggerName(name);
            _default_logger = builder->Build();
            _loggers.insert({name, _default_logger});
        }

        // 删除构造和赋值
        LoggerManager(const LoggerManager &) = delete;
        LoggerManager &operator=(const LoggerManager &) = delete;

    private:
        std::mutex _mutex;
        Logger::ptr _default_logger;
        std::unordered_map<std::string, Logger::ptr> _loggers;
    };

    // 全局日志器建造者子类
    class GlobalLoggerBuilder : public LoggerBuilder {
    public:
        Logger::ptr Build() override {
            assert(!_logger_name.empty());
            if(_formatter == nullptr){
                _formatter = std::make_shared<Formatter>();
            }
            if(_sinks.empty()){
                _sinks.push_back(SinkFactory::create<StdcoutSink>());
            }
            // 根据不同的类型获取不同的日志器
            Logger::ptr logger;
            if (_logger_type == LoggerType::ASYNC_LOGGER){
                auto async_logger = std::make_shared<AsyncLogger>(_logger_name, _limit_level, _formatter, _sinks);
                async_logger->start(_looper_type);
                logger = async_logger;
            }
            else{
                logger = std::make_shared<SyncLogger>(_logger_name, _limit_level, _formatter, _sinks);
            }
            // 将获取到的日志器存放到日志器管理中
            LoggerManager::GetInstance().addlogger(logger);
            return logger;
        }
    };
}

#endif
